import RootContainerConfig from "./typing/root-container-config";
import FieldConfig, {ElementType} from "./typing/field-config";
import FormElement from "./typing/form-element";
import InputFormElement from "./form-elements/input-form-element";
import DyForm from "../DyForm";
import {XOrY} from "../typing/enums";
import {GAP_X, GAP_Y} from "../tailwind";
import SelectFormElement from "./form-elements/select-form-element";
import {merge} from "lodash-es";

/**
 * 包含 fields 的元素
 */
export default class RootContainer {

    private readonly $el: HTMLDivElement
    private readonly fields: FormElement<any>[] = []

    constructor(protected config: RootContainerConfig, protected fieldConfigs: FieldConfig[], protected form: DyForm) {

        this.$el = document.createElement('div')
        this.$el.classList.add("grid", "p-10", 'grow', 'shrink-0', 'h-min',
            this.getColumnClass(this.config.column),
            this.getGap(this.config.elementGapX, XOrY.X),
            this.getGap(this.config.elementGapY, XOrY.Y))
        this.makeElements()
    }

    get el() {
        return this.$el
    }


    /**
     * 获取列数的 class name, 这里这样写是因为使用了 tailwind css , 不支持动态拼接生成class name ,
     * 程序中用的 class name 必须完整的出现在代码中
     * @param column
     * @private
     */
    private getColumnClass(column: number) {
        if (column <= 1) {
            return 'grid-cols-1'
        }
        if (column >= 5) {
            return "grid-cols-5"
        }
        switch (column) {
            case 2:
                return "grid-cols-2"
            case 3:
                return "grid-cols-3"
            case 4:
                return "grid-cols-4"
            default:
                return "grid-cols-5"
        }
    }

    /**
     * 获取列数的 class name, 这里这样写是因为使用了 tailwind css , 不支持动态拼接生成class name ,
     * 程序中用的 class name 必须完整的出现在代码中
     * @param gap 缝隙大小
     * @param xOrY 哪个方向的缝隙
     * @private
     */
    private getGap(gap: number, xOrY: XOrY): string {
        const gapNum = Math.floor(gap);
        if (gapNum <= 0) {
            return undefined
        }

        if (gapNum >= 10) {
            if (xOrY === XOrY.X) {
                return 'gap-x-10'
            } else {
                return 'gap-y-10'
            }
        }
        if (xOrY === XOrY.X) {
            return GAP_X[gapNum]
        } else {
            return GAP_Y[gapNum]
        }
    }

    private makeElements() {
        if (this.fieldConfigs && this.fieldConfigs.length) {
            for (let i = 0; i < this.fieldConfigs.length; i++) {
                const conf = this.fieldConfigs[i]
                this.addEle(conf)
            }
        }
    }

    public addConfig(conf: FieldConfig) {
        this.fieldConfigs.push(conf)
        this.addEle(conf)
    }

    protected addEle(conf: FieldConfig) {
        let el: FormElement<any> = this.makeEle(conf)
        this.fields.push(el)
        this.$el.appendChild(el.getEl())
    }

    removeFormEle(el: FormElement<any>) {
        let index = this.fields.indexOf(el);
        this.fields.splice(index, 1)
        index = this.fieldConfigs.indexOf(el.getConfig());
        this.fieldConfigs.splice(index, 1)
        el.getEl().remove()
    }

    protected makeEle(conf: FieldConfig): FormElement<any> {
        if (conf.type === ElementType.INPUT) {
            return new InputFormElement(conf, this.config.elementHeight, this.form)
        } else if (conf.type === ElementType.SELECT) {
            return new SelectFormElement(conf, this.config.elementHeight, this.form)
        } else {
            throw new Error(`Not support type: ${conf.type}`)
        }
    }

    public collectValues() {
        const result: { [key: string]: any } = {}
        if (this.fields) {
            this.fields.forEach(v => {
                result[v.getName()] = v.getValue()
            })
        }
        return result;
    }

}
